package cz.possoft.client.loader;

import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectStreamClass;

/**
  * ObjectInputStream, which can instantiate classes with classLoaders from GamesDeployerImpl. Useful for loading saved games.
  * 
  * @author mposolda
  */
public class ClassLoaderObjectInputStream extends ObjectInputStream {

	public ClassLoaderObjectInputStream(InputStream is) throws IOException {
		super(is);
	}
	
    protected Class<?> resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException {
    	try {
    		String name = desc.getName();
    		return Class.forName(name, false, findClassLoaderFromClassName(name));
    	}
    	// can theoretically occur in special cases.
    	catch (NullPointerException npe) {
    		System.err.println("NullPointerException during resolving class " + desc.getName() + ". Better thread synchronization is probably needed.");
    		throw new ClassNotFoundException(desc.getName(), npe);
    	}
    }
    
    private ClassLoader findClassLoaderFromClassName(String name) {
    	String basePackage = "cz.possoft.serializable.";
    	if (name.indexOf(basePackage) == -1) {
    		return Thread.currentThread().getContextClassLoader();
    	}
    	else {
    		name = name.substring(name.indexOf(basePackage) + basePackage.length());
    		int dotIndex = name.indexOf('.');
    		if (dotIndex == -1) {
    			return Thread.currentThread().getContextClassLoader();
    		}
    		else {
    			name = name.substring(0, dotIndex);
    			String key = name.substring(0, 1).toUpperCase() + name.substring(1, name.length());
    			// generic key is special case.
    			if ("Generic".equals(key)) {
    				return Thread.currentThread().getContextClassLoader();
    			}
    			try {
    				return GamesDeployerImpl.getInstance().getClassLoaderByKey(key);
    			}
    			catch (JarDeploymentException jde) {
    				throw new RuntimeException(jde);
    			}
    		}
    	}
    }
    
}
